﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Crap4Net
{
    class MethodMatcher
    {
        public static bool IsMatching(MethodSignature first, MethodSignature second)
        {
            //if (first.Equals(second))
            //    return true;
            if ( AssemblyMatch(first.AssemblyName,second.AssemblyName) &&
                 NameSpaceMatch(first.Namespace,second.Namespace) &&
                 TypeMatch(first.TypeName,second.TypeName) &&
                 MethodMatch(first.MethodName,second.MethodName) &&
                 ArgMatch(first.Signature,second.Signature) )
                return true;
            return false;              
        }

        private static bool AssemblyMatch(string assemblyName1, string assemblyName2)
        {
            if ((assemblyName1 =="unknown") || (assemblyName2 == "unknown"))
                return true;
            var name1 = RemoveDLLExtension(assemblyName1);
            var name2 = RemoveDLLExtension(assemblyName2);
            return name1==name2;
        }
        private static string RemoveDLLExtension(string assemblyName)
        {
            if (assemblyName.EndsWith(".dll"))
                return assemblyName.Substring(0, assemblyName.Length - 4);
            else
                return assemblyName;
        }
        private static bool NameSpaceMatch(string nameSpace1, string nameSpace2)
        {
            return nameSpace1 == nameSpace2;
        }
        private static bool TypeMatch(string typeName1, string typeName2)
        {
            return typeName1 == typeName2;
        }

        private static bool MethodMatch(string method1, string method2)
        {
            if (GenericMethod(method1) && GenericMethod(method2) &&
                GenericMethodNameMatch(method1,method2) &&
                NumberOfGenericArgsAreSame(method1, method2))
                return true;

            return method1 == method2;
        }

        private static bool GenericMethod(string method)
        {
            return method.Contains("<");
        }

        private static bool GenericMethodNameMatch(string method1, string method2)
        {
            method1 = NameWithoutGenericArgs(method1);
            method2 = NameWithoutGenericArgs(method2);
            return method1 == method2;
        }

        private static string NameWithoutGenericArgs(string method)
        {
            return method.Split(new char[] { '<' })[0];
        }
        private static bool NumberOfGenericArgsAreSame(string method1, string method2)
        {
            return NumberOfArgs(method1)==NumberOfArgs(method2);
        }
        private static int NumberOfArgs(string method)
        {
            return method.Split(new char[]{','}).Length;
        }
        private static bool ArgMatch(string[] signature1, string[] signature2)
        {
            if (signature1.Length != signature2.Length)
                return false;
            for (int i = 0; i < signature1.Length; i++)
            {
                if (MatchSingleArg(signature1[i], signature2[i]) == false)
                    return false;
            }
            return true;
        }

        private static bool MatchSingleArg(string param1, string param2)
        {
            var argMatcher = new ArgumentMatcher();
            return argMatcher.IsMatching(param1, param2);
        }
    }
}
